# -*- coding: UTF-8 -*-

import web
import json
import urllib
import re
import datetime
import traceback
import sys
import os

sys.path.append(os.path.dirname(__file__))
#import webservices

# conexão ao banco
def db_connect():
    return web.database(dbn = 'mysql', host = 'localhost', db = 'mygado', 
                        user = 'root', passwd = '123', connect_timeout = 10)

def bad_request(message):
    e = web.BadRequest()
    e.message = message
    return e

def where_string(input):
    where_list = []
    for key in input:
        where_list.append(key + " = " + str(web.sqlquote(input[key])))
        
    return " AND ".join(where_list)

def update_string(dic):
    update_list = []
    for key in dic:
        update_list.append(str(key) + " = " + str(web.sqlquote(dic[key])))

    update_str = ", ".join(update_list)
    return update_str

def check_content_type(cont_types):
    if 'CONTENT_TYPE' not in web.ctx.env:
        print repr(web.ctx.env)
        raise bad_request("Content-type not specified.\n" + repr(web.ctx.env))
    
    if web.ctx.env['CONTENT_TYPE'] not in cont_types:
        raise web.HTTPError("415 Unsupported Media Type")


def check_accept():
    # if client specifies Accept, it must accept application/json
    if 'HTTP_ACCEPT' in web.ctx.env:
        accept_list = web.ctx.env['HTTP_ACCEPT'].split(",")
        match = False
        for item in accept_list:
            if re.match(item.split(";")[0].replace("*", ".*"),'application/json'):
                match = True
                break;
        
        if not match:
            raise web.NotAcceptable("Acceptable Content-Types:" + web.ctx.env['HTTP_ACCEPT'])
        
    # if client does not specify Accept, then it accepts anything

def check_input(input, mandatories, optionals = None):
    if len(input) < len(mandatories):
        # too few parameters
        raise bad_request("Bad parameter count (too few parameters).")
    
    if optionals is not None and hasattr(optionals, '__iter__'):        
        if len(input) > len(mandatories) + len(optionals):
            # too many parameters
            raise bad_request("Bad parameter count (too many parameters).")
    
    for k in mandatories:
        if k not in input.keys():
            raise bad_request("Missing required parameter.")
    
    for k in input.keys():    
        if k not in mandatories and (optionals is None or k not in optionals):
            raise bad_request("Unrecognized parameter: " + k)

class DatetimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.strftime("%Y-%m-%d %H:%M:%S")
        else:
            return json.JSONEncoder.default(self, obj)

class CrudBase:
    def __init__(self):
        self.table_name = ''
        
    def GET(self):
        check_accept()        
        
        inp = web.input() # dicionário com todos os parâmetros da URL     
        db = db_connect()
        
        where_str = where_string(inp)
        if len(where_str) > 0:
            result = db.select(self.table_name, where = where_str)
        else:
            result = db.select(self.table_name)
            
        if len(result) == 0:
            raise web.HTTPError("204 No Content")
        
        ret_val = []
        for item in result:
            ret_val.append(dict(item))
        
        web.header('Content-Type', 'application/json')
        return json.dumps(ret_val, cls=DatetimeEncoder)

    def POST(self):    
        print "POST!"    
        check_content_type(['application/json'])
        print "CTYPE OK"
        ids = []
        db = db_connect()
        try:
            
            data1 = web.data()
            print data1
            data = json.loads(web.data())                        
            
            ids = db.multiple_insert(self.table_name, data)

        except ValueError as exc:
            raise bad_request(str(exc))        
        # stringly-typed exception handler
        # this is made so that I don't have to guess and import the module
        # that contains the IntegrityError class (and thus depend on it)
        except Exception as exc:
            if exc.__class__.__name__ == 'IntegrityError':
                raise web.Conflict("Integrity error (duplicate entry?)")

            else:
                raise web.InternalError(exc.__class__.__name__ + ":" + str(exc))
            
        if len(ids) > 0:
#            urls = []
#            for item in ids:
#                # reconstruct base URL
#                url = web.ctx.env['wsgi.url_scheme'] + '://'
#                if 'HTTP_HOST' in web.ctx.env:
#                    url += web.ctx.env['HTTP_HOST']# + ':' \
#                    #+ web.ctx.env['SERVER_PORT']
#                
#                # add link
#                url += urllib.quote(web.ctx.env['REQUEST_URI'])
#                url += '?id=' + str(item)
#                
#                web.header('Location', url)
#                urls.append(url)
                
            web.header('Content-Type', 'application/json')
            #raise web.Created(json.dumps(urls))
            raise web.Created(ids)

    def PUT(self):

        check_content_type(['application/json'])
        check_accept()

        inp = web.input()
        db = db_connect()
        
        try:
            data = json.loads(web.data())
        except ValueError as exc:
            raise bad_request(str(exc))
        
        if len(data) == 0:
            raise bad_request("No data to update")
        
        where_str = where_string(inp)
        update_str = update_string(data)
        
        if len(where_str) == 0:
            raise bad_request("At least one filter parameter must be given.")
        
        if len(update_str) == 0:
            raise bad_request("No data to update.")
        
        try:
            count = db.query(" UPDATE " + self.table_name + " SET " 
                             + update_str + " WHERE " + where_str)  
            web.header('Content-Type', 'application/json')
            return json.dumps(count)
        
        # stringly-typed exception handler
        # this is made so that I don't have to guess and import the module
        # that contains the IntegrityError class (and thus depend on it)
        except Exception as exc:
            if exc.__class__.__name__ == 'IntegrityError':
                raise web.Conflict("Integrity error (duplicate entry?)")

            else:
                raise web.InternalError(exc.__class__.__name__ + ":" + str(exc))

    def DELETE(self):        
        inp = web.input()
        db = db_connect()
        
        where_str = where_string(inp)
        #if len(where_str) == 0:
            #raise bad_request("At least one filter parameter must be given.")
        
        count = 0
        try:
            if len(where_str) > 0:
                count = db.delete(self.table_name, where=where_str)
            else:
                count = db.query("DELETE FROM "+self.table_name)
            
            web.header('Content-Type', 'application/json')
            return json.dumps(count)
        
        # stringly-typed exception handler
        # this is made so that I don't have to guess and import the module
        # that contains the IntegrityError class (and thus depend on it)
        except Exception as exc:
            if exc.__class__.__name__ == 'IntegrityError':
                raise web.Conflict("Integrity error (duplicate entry?)")

            else:
                raise web.InternalError(exc.__class__.__name__ + ":" + str(exc))
